#pragma once
#include "compat.h"
#include <limits.h>
#include <locale.h>
#include <string>
#include <system_error>
#include <sstream>

namespace Utility
{
namespace Details
{

/// <summary>
/// Our own implementation of alpha numeric instead of std::isalnum to avoid
/// taking global lock for performance reasons.
/// </summary>
inline bool __cdecl is_alnum(const unsigned char uch) _NOEXCEPT
{ // test if uch is an alnum character
// special casing char to avoid branches
// clang-format off
static _CONSTEXPR bool is_alnum_table[UCHAR_MAX + 1] = {
	/*        X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF */
	/* 0X */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	/* 1X */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	/* 2X */   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	/* 3X */   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0-9 */
	/* 4X */   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A-Z */
	/* 5X */   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
	/* 6X */   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a-z */
	/* 7X */   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
	/* non-ASCII values initialized to 0 */
};
// clang-format on
return (is_alnum_table[uch]);
}

/// <summary>
/// Convert a string to lowercase in place.
/// </summary>
/// <param name="target">The string to convert to lowercase.</param>
void inplace_tolower(std::string& target) _NOEXCEPT;

}

namespace Conversions
{
namespace Details
{

template<typename Source>
std::string print_string(const Source& val)
{
	std::ostringstream oss;
	oss.imbue(std::locale::classic());
	oss << val;
	if (oss.bad())
	{
		throw std::bad_cast();
	}
	return oss.str();
}

inline const std::string& print_string(const std::string& val) { return val; }

template<typename Target>
Target scan_string(const std::string& str)
{
	Target t;
	std::istringstream iss(str);
	iss.imbue(std::locale::classic());
	iss >> t;
	if (iss.bad())
	{
		throw std::bad_cast();
	}
	return t;
}

inline const std::string& scan_string(const std::string& str) { return str; }

}
}
}